package com.mygdx.game;


import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.*;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;
import com.re6g3y.game.mulitThread.Actions.RunAction;
import com.re6g3y.game.mulitThread.MainAssigner;
import com.re6g3y.game.mulitThread.Node;
import com.badlogic.gdx.physics.box2d.World;
import com.mygdx.game.tools.PhysicsEditorShapeLibrary;

import java.util.*;

/**
 * @author D.Winter
 * http://www.cnblogs.com/dwinter/
 * Android 游戏引擎libgdx之Box2D 案例实践——弹球
 */
public class ball extends ApplicationAdapter {

    SpriteBatch batch;
    private com.badlogic.gdx.physics.box2d.World world ;
//    private Texture ball;
    private com.re6g3y.game.textureUitls.TextureLoader textureLoader=new com.re6g3y.game.textureUitls.TextureLoader();
//    private Texture flare;
    private Body body;
    private Body groundBody;
    Box2DDebugRenderer box2DDebugRenderer;
    OrthographicCamera camera;
    PhysicsEditorShapeLibrary physicsEditorShapeLibrary=new PhysicsEditorShapeLibrary();

    MainAssigner ma=new MainAssigner(8);

    List<Body> bodys=new ArrayList<Body>(100);

    @Override
    public void create() {

        Gdx.gl.glClearColor(0.05f, 0.05f, 0.05f, 1F);

        box2DDebugRenderer = new Box2DDebugRenderer();

        camera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0);
        camera.update();

        batch = new SpriteBatch();
        world = new World(new Vector2(0, -00000f), true);
        world.setContactListener(new ContactListener() {
            @Override
            public void beginContact(Contact contact) {
                if(!contact.isTouching())return;
                if("rect".equals(contact.getFixtureB().getBody().getUserData())||"rect".equals(contact.getFixtureA().getBody().getUserData()))return;
                Body a=contact.getFixtureA().getBody();
                Body b=contact.getFixtureB().getBody();
                Vector2 v=a.getPosition().cpy();
                v=v.sub(b.getPosition());
                Vector2 conPit=contact.getWorldManifold().getPoints()[0];

//                batch.draw(ball,conPit.x-5,conPit.y-5,10,10);
//                font.draw(batch, "o",conPit.x-10, conPit.y-10);

//                a.applyLinearImpulse(v.nor().scl(15f*Math.max(a.getMass(),b.getMass())),conPit,true);
//                b.applyLinearImpulse(v.nor().scl(-15f*Math.max(a.getMass(),b.getMass())),conPit,true);
            }

            @Override
            public void endContact(Contact contact) {

            }

            @Override
            public void preSolve(Contact contact, Manifold oldManifold) {

            }

            @Override
            public void postSolve(Contact contact, ContactImpulse impulse) {
            }
        });
        textureLoader.load("badlogic.jpg");
        textureLoader.load("graphics/misslise/shell_gauss_cannon.png");

//        ball = new Texture("badlogic.jpg");
        // Create edges around the entire screen
        BodyDef bd = new BodyDef();
        bd.position.set(2, 2);
        groundBody = world.createBody(bd);
        EdgeShape edge = new EdgeShape();
        edge.set(new Vector2(0f, 0f), new Vector2(Gdx.graphics.getWidth(), 0f));
        FixtureDef boxShapeDef = new FixtureDef();
        boxShapeDef.shape = edge;
        groundBody.createFixture(boxShapeDef);
        groundBody.setUserData("rect");


        groundBody = world.createBody(bd);
        edge = new EdgeShape();
        edge.set(new Vector2(0f, 0f), new Vector2(0f, Gdx.graphics.getHeight()));
        boxShapeDef = new FixtureDef();
        boxShapeDef.shape = edge;
        groundBody.createFixture(boxShapeDef);
        groundBody.setUserData("rect");

        groundBody = world.createBody(bd);
        edge = new EdgeShape();
        edge.set(new Vector2(0f, Gdx.graphics.getHeight() - 5), new Vector2(Gdx.graphics.getWidth() - 5, Gdx.graphics.getHeight() - 5));
        boxShapeDef = new FixtureDef();
        boxShapeDef.shape = edge;
        groundBody.createFixture(boxShapeDef);
        groundBody.setUserData("rect");

        groundBody = world.createBody(bd);
        edge = new EdgeShape();
        edge.set(new Vector2(Gdx.graphics.getWidth() - 5, 0f), new Vector2(Gdx.graphics.getWidth() - 5, Gdx.graphics.getHeight() - 5));
        boxShapeDef = new FixtureDef();
        boxShapeDef.shape = edge;
        groundBody.createFixture(boxShapeDef);
        groundBody.setUserData("rect");


        physicsEditorShapeLibrary.load(Gdx.files.internal("graphics/misslise/shell_gauss_cannon.xml").file(),"flare",1/3f);
        // Create ball body and shape
        for (int i = 0; i < sum; i++) {
            Vector2 pos=new Vector2(Gdx.graphics.getWidth()/2+(float) (Math.random()-0.5)*Gdx.graphics.getWidth()/1.5f, Gdx.graphics.getHeight()/2+(float)(Math.random()-0.5)*Gdx.graphics.getHeight()/1.5f) ;
            Body tmp=physicsEditorShapeLibrary.createBody("shell_gauss_cannon",pos,world);
            tmp.setAngularVelocity(MathUtils.random(30));
            bodys.add(tmp);
            /*
            BodyDef ballBodyDef = new BodyDef();
            ballBodyDef.type = BodyType.DynamicBody;
            ballBodyDef.position.set(Gdx.graphics.getWidth()/2+(float) (Math.random()-0.5)*Gdx.graphics.getWidth()/1.5f, Gdx.graphics.getHeight()/2+(float)(Math.random()-0.5)*Gdx.graphics.getHeight()/1.5f);
            body = world.createBody(ballBodyDef);
            FixtureDef ballShapeDef = new FixtureDef();
            if(Math.random()>0.5) {
                CircleShape circle = new CircleShape();
                circle.setRadius(5 + (float) Math.random() * (float) Math.random() * 15);
                ballShapeDef.shape = circle;
            }else {
                PolygonShape rect = new PolygonShape();
                rect.setAsBox(5 + (float) Math.random() * (float) Math.random() * 15, 5 + (float) Math.random() * (float) Math.random() * 15);
                ballShapeDef.shape=rect;
            }
            ballShapeDef.density = 1.0f;
            ballShapeDef.friction = 0.2f;
            ballShapeDef.restitution = 0.8f;
            body.createFixture(ballShapeDef);
//            body.setBullet(true);
            body.setLinearVelocity((float) Math.random()*10,(float) Math.random()*10);
            bodys.add(body);
            body.setUserData("ball");*/
        }
        gen = new FreeTypeFontGenerator( Gdx.files.internal("msjh.ttf"));

//        if(font!=null)font.dispose();
        FreeTypeFontGenerator.FreeTypeFontParameter par=new FreeTypeFontGenerator.FreeTypeFontParameter();
        par.color=Color.CYAN;
        par.size=20;

        par.characters+="非并行";
        par.borderWidth=3f;
        par.borderColor=Color.PINK;

        par.shadowColor=Color.NAVY;
        par.shadowOffsetX=3;
        par.shadowOffsetY=3;

        font = gen.generateFont(par);

        pixmap = new Pixmap(Gdx.graphics.getWidth(), Gdx.graphics.getHeight(), Pixmap.Format.RGBA8888);
    }

    int sum=100;
    int calnum=0;

    FreeTypeFontGenerator gen;
    BitmapFont font;
    private void writeFPS(){
        font.draw(batch, "并行",3, 20*3);
        font.draw(batch, "ALL:"+calnum,3, 20*2);
        calnum=0;
        font.draw(batch, "FPS:" + Gdx.graphics.getFramesPerSecond(),3, 20);
    }

    Pixmap pixmap ;

    boolean arr[]=new boolean[sum];
    private void grivate(){

        pixmap.setColor(0);
        pixmap.fill();
        pixmap.setColor(Color.ROYAL);

        final int dist=500;
        for (int i = 0; i < sum; i++) {
            final int index=i;
            Node nd=new Node() {
                @Override
                public void run() {
//                    final List<Body> list=new ArrayList<Body>(50);
                    final Set<Body> list=new LinkedHashSet<Body>(50);
                    final Body b = bodys.get(index);
                    b.applyAngularImpulse(5*b.getMass()*(-b.getAngularVelocity()),false);

                    final Body b2 = bodys.get((index+1)%sum);
//                    Vector2 target=new Vector2(arr[index]?100:1920-100,1080.0f/2);//
                    Vector2 target=b2.getPosition();
                    if(b.getPosition().x<300)arr[index]=false;
                    else if(b.getPosition().x>1920-300)arr[index]=true;
                    Vector2 toCenter=target.cpy().sub(b.getPosition());
                    Vector2 pointTo=new Vector2(MathUtils.sin(b.getAngle()),-MathUtils.cos(b.getAngle()));

                    pixmap.drawLine((int) b.getPosition().x, pixmap.getHeight()-(int) b.getPosition().y, (int) target.x, pixmap.getHeight()-(int)target.y);

                    b.applyAngularImpulse(b.getMass()*(-toCenter.angle(pointTo)/3),false);

                    b.applyForceToCenter(pointTo.scl(100*b.getMass()),false);
//                    QueryCallback qc= new QueryCallback() {
//                        @Override
//                        public boolean reportFixture(Fixture fixture) {
//                            if(fixture.getBody()!=b&&b.getPosition().dst(fixture.getBody().getPosition())<dist)list.add(fixture.getBody());
//                            return true;
//                        }
//                    };
//                    world.QueryAABB(qc,b.getPosition().x-dist,b.getPosition().y-dist,b.getPosition().x+dist,b.getPosition().y+dist);
//                    calnum+=list.size();
//
//                    for(Body bs: list){
//                        pixmap.drawLine((int) b.getPosition().x, Gdx.graphics.getHeight()-(int) b.getPosition().y, (int) bs.getPosition().x, Gdx.graphics.getHeight()-(int) bs.getPosition().y);
//                        Vector2 f = bs.getPosition().sub(b.getPosition());
//                        float dists=f.len();
//                        float g = 1000 * (b.getMass() * bs.getMass())/(dists*dists) * Gdx.graphics.getDeltaTime();
//                        f.nor().scl(g);
////                        b.applyForce(f, b.getPosition(), false);
//                    }
                }
            };
            nd.setNodeAction(RunAction.getInstance());
            ma.add(nd);
        }
        ma.notifyAndWaitFinish();

//        pixmap.dispose();
//        if(result!=null)result.dispose();
        if(result==null) result = new Texture(pixmap);
        else result.draw(pixmap,0,0);
        batch.draw(result,0,0);
    }
    Texture result;

    double time=1;
    @Override
    public void render() {
        Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
//        box2DDebugRenderer.render(world, camera.combined);
        batch.begin();

        if((time-=Gdx.graphics.getDeltaTime())>0);

        Texture flare=textureLoader.get("shell_gauss_cannon.png");
        TextureRegion region = new TextureRegion(flare, 0,0,flare.getWidth(),flare.getHeight());
        for(Body b:bodys){
            Vector2 conPit=b.getPosition();
            float h=flare.getHeight()/1.0f;
            float w=flare.getWidth()/1.0f;
            synchronized (batch) {
                batch.draw(region, conPit.x - w * 0.5f, conPit.y - h * 0.5f, w * 0.5f, h * 0.5f, w, h, 3, 3, (float) Math.toDegrees(b.getAngle() + Math.PI));
            }
        }
        grivate();
        if(time<-1)time=1;

        writeFPS();
        world.step(Math.min(1/20f,Gdx.graphics.getDeltaTime()), 5, 5);
//        world.step(Gdx.app.getGraphics().getDeltaTime(), 2, 2);
        batch.end();
    }

    @Override
    public void dispose() {
//         renderer.dispose();
        world.dispose();
        super.dispose();
        gen.dispose();
        font.dispose();
        ma.dispose();
    }
}